﻿namespace SugarTank.Mobile.Managers
{
    using System;
    using System.Device.Location;
    using Contracts;
    using Helpers;

    public class GeographicManager : IGeographicManager
    {
        /// <summary>
        /// The phone geo corodinate watcher.
        /// </summary>
        private GeoCoordinateWatcher watcher;

        #region IGeographicManager Members

        /// <summary>
        /// Occurs when [geo watcher position changed].
        /// </summary>
        public event EventHandler<EventArgs<GeoPositionChangedEventArgs<GeoCoordinate>>> GeoWatcherPositionChanged;

        /// <summary>
        /// Occurs when [geo watcher started].
        /// </summary>
        public event EventHandler<EventArgs> GeoWatcherStarted;

        /// <summary>
        /// Occurs when [geo watcher failed to start].
        /// </summary>
        public event EventHandler<EventArgs> GeoWatcherFailedToStart;

        /// <summary>
        /// Occurs when [geo watcher stopped].
        /// </summary>
        public event EventHandler<EventArgs> GeoWatcherStopped;

        /// <summary>
        /// Occurs when [geo watcher status changed].
        /// </summary>
        public event EventHandler<EventArgs<GeoPositionStatus>> GeoWatcherStatusChanged;

        /// <summary>
        /// Starts the geo watcher.
        /// </summary>
        /// <param name="movementThreshold">The movement threshold.</param>
        /// <param name="accuracy">The accuracy.</param>
        public void StartGeoWatcher(double movementThreshold, GeoPositionAccuracy accuracy)
        {
            this.watcher = new GeoCoordinateWatcher(accuracy);
            this.watcher.MovementThreshold = movementThreshold;

            this.watcher.PositionChanged += this.OnWatcherPositionChanged;
            this.watcher.StatusChanged += this.OnWatcherStatusChanged;

            if (!this.watcher.TryStart(false, TimeSpan.FromSeconds(10)))
            {
                this.GeoWatcherFailedToStart.FireEvent(this, () => EventArgs.Empty);
                return;
            }

            this.GeoWatcherStarted.FireEvent(this, () => EventArgs.Empty);
        }

        /// <summary>
        /// Stops the geo watcher.
        /// </summary>
        public void StopGeoWatcher()
        {
            this.watcher.Dispose();
            this.GeoWatcherStopped.FireEvent(this, () => EventArgs.Empty);
        }

        #endregion

        /// <summary>
        /// Called when [watcher position changed].
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The instance containing the event data.</param>
        private void OnWatcherPositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e)
        {
            this.GeoWatcherPositionChanged.FireEvent(sender, () => new EventArgs<GeoPositionChangedEventArgs<GeoCoordinate>>(e));
        }

        /// <summary>
        /// Called when [watcher status changed].
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Device.Location.GeoPositionStatusChangedEventArgs"/> instance containing the event data.</param>
        private void OnWatcherStatusChanged(object sender, GeoPositionStatusChangedEventArgs e)
        {
            this.GeoWatcherStatusChanged.FireEvent(sender, () => new EventArgs<GeoPositionStatus>(e.Status));
        }
    }
}